import {ObjectItem, ObjectStorage} from "./objectStorage";
import OSS from 'ali-oss';
import { StorageConfig } from "./type";
import { Readable } from "stream";
import path from "path";
import * as fs from 'fs-extra';

export class OssStorage implements ObjectStorage {
    private ossClient: OSS;

    constructor(private config?: StorageConfig) {
    }

    private async buildOSSClient(): Promise<OSS> {
        const options = {} as OSS.Options;
        if (this.config) {
            options.endpoint = this.config.host;
            options.bucket = this.config.bucket;
            options.accessKeyId = this.config.accessKey;
            options.accessKeySecret = this.config.accessSecret;
        }
        return new OSS(options);
    }

    private async getClient(): Promise<OSS> {
        if (!this.ossClient) {
            this.ossClient = await this.buildOSSClient();
        }
        return this.ossClient;
    }

    // 添加支持进度回调的 fPutObject 方法
    async fPutObjectWithProgress(
        bucket: string, 
        objectName: string, 
        filePath: string,
        progressCallback?: (percentage: number) => void
    ): Promise<any> {
        const client = await this.getClient();
        
        const result = await client.multipartUpload(objectName, filePath, {
            progress: (p: number) => {
                if (progressCallback) {
                    // 将进度转换为百分比 (0-100)
                    const percentage = Math.round(p * 100);
                    progressCallback(percentage);
                }
            }
        });
        return result;
    }

    async fGetObject(bucket: string, objectName: string, filePath: string): Promise<any> {
        const client = await this.getClient();
        const dir = path.dirname(filePath);
        await fs.ensureDir(dir);
        const result = await client.get(objectName, filePath, {bucket});
        return result;
    }

    async fPutObject(bucket: string, objectName: string, filePath: string): Promise<any> {
        const client = await this.getClient();
        const result = await client.put(objectName, filePath, {bucket});
        return result;
    }

    async getObject(bucket: string, objectName: string): Promise<Readable> {
        const client = await this.getClient();
        const result = await client.getStream(objectName, {bucket});
        return result.stream as Readable;
    }

    async getString(bucket: string, objectName: string, encoding: BufferEncoding): Promise<string> {
        const client = await this.getClient();
        const result = await client.get(objectName, {bucket});
        return result.content.toString(encoding);
    }

    async listObjects(bucket: string, objectName: string): Promise<ObjectItem[]> {
        const client = await this.getClient();

        // 增加容错处理：当无对象时返回空数组
        const result = await client.list(
            { prefix: objectName, bucket },
            { timeout: 5000 }
        ).catch(() => ({ objects: [] }));

        return (result.objects || [])
            .filter(obj => !obj.name.endsWith('/'))
            .map((obj: any) => ({
                name: path.basename(obj.name),
                value: obj.name,
                lastModified: obj.lastModified
            }));
    }

    async putObject(bucket: string, objectName: string, content: string | Buffer): Promise<any> {
        const client = await this.getClient();
        const result = await client.put(objectName, Buffer.from(content), {bucket});
        return result;
    }

    async removeObject(bucket: string, objectName: string): Promise<any> {
        const client = await this.getClient();
        const result = await client.delete(objectName, {bucket});
        return result;
    }

    async append(bucket: string, objectName: string, content: string): Promise<any> {
        let originalContent = '';
        try {
            originalContent = await this.getString(bucket, objectName, "utf-8");
        } catch (e) {
            console.debug(`❗️Storage AppendWarning ==> ${e.code}: ${e.message} objectName: ${objectName}`);
        }
        const data = `${originalContent}${content}`;
        await this.putObject(bucket, objectName, data);
    }

    async signatureUrl(bucket: string, objectName): Promise<any> {
        const client = await this.getClient();
        return client.signatureUrl(objectName, { method: 'GET' });
    }

}

/**
let ossStorage = new OssStorage({
    "host": "oss-cn-shanghai.aliyuncs.com",
    "bucket": "suanpan-public",
    "accessKey": "LTAI5tQFGskQXNP5bbPgv1bd",
    "accessSecret": "pzCXEMfxzLLVMCNF1g1OuTCWWLyuGp"
} as StorageConfig);


(async () => {
    try {

        await ossStorage.fPutObjectWithProgress(
            'suanpan-public',
            'nacos-server-2.2.3.zip',
            '/Users/luotao/Desktop/nacos-server-2.2.3.zip',
            (percentage) => {
                console.log(`上传进度: ${percentage}%`);
            }
        );

        // await ossStorage.fGetObject("suanpan-public", "suanpan-clear.exe", "./suanpan-clear.exe");

        // let str = await ossStorage.getString("suanpan-public", "version.json", "utf-8");
        // const a =  JSON.parse(str);
        // console.log(a)
        
        // await ossStorage.fPutObject("suanpan-public", "sh-dc/index.ts", "./src/common/objectStorage/index.ts");
    } catch (error) {
        console.error("Download failed:", error);
    }
})();
*/